/**
 * Simple statically-typed programming language with functions and variables
 * taken from the "Language Implementation Patterns" book.
 *
 * @see http://media.pragprog.com/titles/tpantlr2/code/examples/Cymbol.g4
 */
////////////////////////////////////////////
grammar Cymbol;

@header {
package com.taotao.antlr4.cymbol;
}
////////////////////////////////////////////
prog : (varDecl | functionDecl)* EOF ;

//varDecl : type ID ';'
//        | type ID '=' expr ';'
//        ;
varDecl : type ID ('=' expr)? ';' ;

type : 'int' | 'double' | 'void' ;

// type ID, type ID, type ID, ...
functionDecl : type ID '(' formalParameters? ')' block ;

formalParameters : formalParameter (',' formalParameter)* ;

formalParameter : type ID ;

block : '{' stat* '}' ;

stat : block    # BlockStat  // 加标签 则listener和visitor会生成标签名称对应的方法，不加标签则只会对stat 生成方法
     | varDecl  # VarDeclStat
     | 'if' expr 'then' stat ('else' stat)? # IfStat
     | 'return' expr? ';'   # ReturnStat
     | expr '=' expr ';'    # AssignStat
     | expr ';'             # ExprStat
     ;
////////////////////////////////////////////
expr: ID '(' exprList? ')'    # Call // function call
    | expr '[' expr ']'       # Index // array subscripts
    | op = '-' expr           # Negate // right association
    | op = '!' expr           # Not // right association
    | <assoc = right> lhs = expr '^' rhs = expr # Power   // 幂运算右结合
    | lhs = expr (op = '*' | op = '/') rhs = expr     # MultDiv   //  op 是对操作符起别名 ；lhs  rhs 是对左右表达式 起别名，都会在MultDivcontext类中生成对应的变量，
    | lhs = expr (op = '+' | op = '-') rhs = expr     # AddSub
    | lhs = expr (op = '==' | op = '!=') rhs = expr   # EQNE
    | '(' expr ')'            # Parens
    | ID                      # Id
    | INT                     # Int
    ;

exprList : expr (',' expr)* ;

////////////////////////////////////////////
// You can use "Alt + Insert" to automatically generate
// the following lexer rules for literals in the grammar above.
// Remember to check and modify them if necessary.

SEMI : ';' ;
COMMA : ',' ;
LPAREN : '(' ;
RPAREN : ')' ;
LBRACK : '[' ;
RBRACK : ']' ;
LBRACE : '{' ;
RBRACE : '}' ;

IF : 'if' ;
THEN : 'then' ;
ELSE : 'else' ;
RETURN : 'return' ;

INTTYPE : 'int' ;
DOUBLETYPE : 'double' ;
VOIDTYPE : 'void' ;

ADD : '+' ;
SUB : '-' ;
MUL : '*' ;
DIV : '/' ;

EQ : '=' ;
NE : '!=' ;
EE : '==' ;
////////////////////////////////////////////
WS  : [ \t\n\r]+ -> skip ;

ID : LETTER (LETTER | DIGIT)* ;
INT : DIGIT+ ;

fragment LETTER : [a-zA-Z] ;
fragment DIGIT : [0-9] ;
////////////////////////////////////////////